{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 尝试在MNIST数据集上建立一个分类器，使它在测试集上的精度超过97%。\n",
    "提示： KNeighborsClassifier 非常适合这个任务。你只需要找出一个好的超参数值(试以下对权重和超参数 n_neighbors进行网格搜索)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  数据获取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda3\\lib\\site-packages\\sklearn\\utils\\deprecation.py:85: DeprecationWarning: Function fetch_mldata is deprecated; fetch_mldata was deprecated in version 0.20 and will be removed in version 0.22. Please use fetch_openml.\n",
      "  warnings.warn(msg, category=DeprecationWarning)\n",
      "D:\\Anaconda3\\lib\\site-packages\\sklearn\\utils\\deprecation.py:85: DeprecationWarning: Function mldata_filename is deprecated; mldata_filename was deprecated in version 0.20 and will be removed in version 0.22. Please use fetch_openml.\n",
      "  warnings.warn(msg, category=DeprecationWarning)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'DESCR': 'mldata.org dataset: mnist-original',\n",
       " 'COL_NAMES': ['label', 'data'],\n",
       " 'target': array([0., 0., 0., ..., 9., 9., 9.]),\n",
       " 'data': array([[0, 0, 0, ..., 0, 0, 0],\n",
       "        [0, 0, 0, ..., 0, 0, 0],\n",
       "        [0, 0, 0, ..., 0, 0, 0],\n",
       "        ...,\n",
       "        [0, 0, 0, ..., 0, 0, 0],\n",
       "        [0, 0, 0, ..., 0, 0, 0],\n",
       "        [0, 0, 0, ..., 0, 0, 0]], dtype=uint8)}"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 获取数据\n",
    "from sklearn.datasets import fetch_mldata\n",
    "mnist = fetch_mldata('MNIST original',data_home='./datasets/minst')\n",
    "mnist"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(70000, 784)"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 将数据划分为训练数据 和测试数据\n",
    "X, y = mnist[\"data\"], mnist[\"target\"]\n",
    "X.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模型训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',\n",
       "                     metric_params=None, n_jobs=3, n_neighbors=3, p=2,\n",
       "                     weights='uniform')"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用 KNeighborsClassifier模型进行分类\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "knn_clf = KNeighborsClassifier(n_jobs=3, n_neighbors=3)\n",
    "knn_clf.fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 性能评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对模型进行评分\n",
    "from sklearn.model_selection import cross_val_score\n",
    "scores = cross_val_score(knn_clf, X_train, y_train, cv=3, scoring=\"accuracy\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.96110778, 0.96139807, 0.96364455])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "scores"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import f1_score\n",
    "from sklearn.model_selection import cross_val_predict\n",
    "y_train_knn_pred = cross_val_predict(knn_clf, X_train, y_train, cv=3)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9680932369067182"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# F1值评估模型, 标签权重\n",
    "f1_score(y_train, y_train_knn_pred, average=\"weighted\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9683615045706023"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 准确率\n",
    "from sklearn.metrics import precision_score, recall_score\n",
    "precision_score(y_train, y_train_knn_pred, average='weighted')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9676655050197676"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 召回率\n",
    "recall_score(y_train, y_train_knn_pred, average='macro')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[5879,    6,    6,    1,    0,    7,   18,    2,    1,    3],\n",
       "       [   1, 6698,   17,    0,    3,    1,    4,   12,    1,    5],\n",
       "       [  58,   92, 5612,   20,    8,    8,   12,  112,   26,   10],\n",
       "       [   8,   26,   36, 5866,    3,   72,    5,   44,   38,   33],\n",
       "       [   6,   68,    1,    1, 5578,    0,   19,    9,    1,  159],\n",
       "       [  20,   22,    3,   73,    7, 5182,   63,    5,   13,   33],\n",
       "       [  28,   17,    2,    0,    5,   28, 5836,    0,    2,    0],\n",
       "       [   4,   88,   14,    2,   20,    2,    0, 6063,    2,   70],\n",
       "       [  23,  103,   18,   94,   42,  118,   34,   19, 5320,   80],\n",
       "       [  16,   20,    4,   55,   50,   13,    5,   83,   14, 5689]],\n",
       "      dtype=int64)"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 混淆矩阵\n",
    "from sklearn.metrics import confusion_matrix\n",
    "conf_mx = confusion_matrix(y_train, y_train_knn_pred)\n",
    "conf_mx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x1d6df0eb688>"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 288x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "plt.matshow(conf_mx, cmap=plt.cm.gray)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x1d6c9ba2808>"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 288x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "row_sums = conf_mx.sum(axis=1, keepdims=True)\n",
    "norm_conf_mx = conf_mx / row_sums\n",
    "np.fill_diagonal(norm_conf_mx, 0)\n",
    "plt.matshow(norm_conf_mx, cmap=plt.cm.gray)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模型调参"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fitting 3 folds for each of 15 candidates, totalling 45 fits\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Parallel(n_jobs=3)]: Using backend LokyBackend with 3 concurrent workers.\n",
      "[Parallel(n_jobs=3)]: Done  12 tasks      | elapsed: 81.0min\n",
      "[Parallel(n_jobs=3)]: Done  45 out of  45 | elapsed: 306.6min finished\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "GridSearchCV(cv=3, error_score='raise-deprecating',\n",
       "             estimator=KNeighborsClassifier(algorithm='auto', leaf_size=30,\n",
       "                                            metric='minkowski',\n",
       "                                            metric_params=None, n_jobs=None,\n",
       "                                            n_neighbors=5, p=2,\n",
       "                                            weights='uniform'),\n",
       "             iid='warn', n_jobs=3,\n",
       "             param_grid=[{'n_neighbors': range(1, 30, 2)}],\n",
       "             pre_dispatch='2*n_jobs', refit=True, return_train_score=False,\n",
       "             scoring='accuracy', verbose=5)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 网格搜索\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "\n",
    "param_grid = [\n",
    "    {'n_neighbors': range(1,30,2)},\n",
    "]\n",
    "\n",
    "knn_clf = KNeighborsClassifier()\n",
    "grid_search = GridSearchCV(knn_clf, param_grid, cv = 3,\n",
    "                          scoring = 'accuracy',\n",
    "                          n_jobs = 3,\n",
    "                          verbose= 5)\n",
    "grid_search.fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'n_neighbors': 3}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grid_search.best_params_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best: 0.968167 using {'n_neighbors': 3}\n"
     ]
    }
   ],
   "source": [
    "print(\"Best: %f using %s\" % (grid_search.best_score_,grid_search.best_params_))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',\n",
       "                     metric_params=None, n_jobs=None, n_neighbors=3, p=2,\n",
       "                     weights='uniform')"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grid_search.best_estimator_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'grid_search' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-1-692cd6f24c99>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mcvres\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgrid_search\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcv_results_\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[0mmeans\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgrid_search\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcv_results_\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'mean_test_score'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[0mparams\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgrid_search\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcv_results_\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'params'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mmean_score\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mparams\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mzip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcvres\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"mean_test_score\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcvres\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"params\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'grid_search' is not defined"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "cvres = grid_search.cv_results_\n",
    "means = grid_search.cv_results_['mean_test_score']\n",
    "params = grid_search.cv_results_['params']\n",
    "for mean_score, params in zip(cvres[\"mean_test_score\"], cvres[\"params\"]):\n",
    "    print(mean_score, params)\n",
    "    list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 画图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib.ticker import MultipleLocator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "# Data for plotting\n",
    "list_a = [i['n_neighbors'] for i in grid_search.cv_results_['params']]\n",
    "t = means\n",
    "s = list_a\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "ax.plot(s, t)\n",
    "# ax.plot(t)\n",
    "ax.set(xlabel='n_neighbors', ylabel='mean_test_score',\n",
    "       title='Best Superparams')\n",
    "ax.grid()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 在测试数据集上查看准确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9705\n"
     ]
    }
   ],
   "source": [
    "print(knn_clf.score(X_test, y_test))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
